/*
********************************************************************************
* Copyright (C) 2021, xiang.D <dx_65535@163.com>.
* All right reserved.
*
* File Name   : state.h
* Author      :
* Version     : V1.0
* Description :
* Journal     : 2021-12-17 version v1.0
* Brief       : Blog: https://blog.csdn.net/qq_38750572?spm=1001.2014.3001.5343
* Others      :
                Compile command: make
********************************************************************************
*/
#ifndef __ELEVATOR_SRV_H__
#define __ELEVATOR_SRV_H__

#include <thread>
#include <vector>

// 楼层范围均从0开始，涉及负数，显示做偏移
#define MAX_FLOOR   20
#define MIN_FLOOR   0

// 消息类型枚举集
typedef enum
{
    SIG_ID_ANY              = 0x00,
    SIG_ID_POWER_ON,
    SIG_ID_POWER_OFF,
    SIG_ID_TAKE_UP_ORDER,       // 预约上行
    SIG_ID_TAKE_DOWN_ORDER,     // 预约下行
    SIG_ID_ARRIVE_FLOOR,        // 到指定楼层
    SIG_ID_EXIT,                // 暂停运行
    SIG_ID_MAX
}EMsgType;

// 电梯预约乘坐方向
typedef enum
{
    TAKE_NONE               = 0x00,
    TAKE_UP                 = 0x01,
    TAKE_DOWN               = 0x02,
    TAKE_ALL
}ETakeDirection;

// 一级状态:
typedef enum
{
    LEV1_ANY                = 0x00,
    LEV1_DOOR_OPEN,             // 开门
    LEV1_DOOR_CLOSE             // 关门
}EElevatorDoorState;

#define MAX_STRING  10
#define LEV2_STRING {"ANY", "UP", "DOWN", "EXIT", "IDLE"}

//二级状态:
typedef enum
{
    LEV2_ANY                = 0x00,
    LEV2_UP,                    // 上行
    LEV2_DOWN,                  // 下行
    LEV2_EXIT,                  // 维修
    LEV2_IDLE                   // 空闲
}EElevatorRunState;

// 预约乘坐信息
typedef struct
{
    ETakeDirection direct;
    int floor;
}STakeOrderInfo;

// 消息包
typedef struct
{
    EMsgType    type;
    void        *content;
}SMsgPacket;

typedef enum
{
    ORDER_CLEAR             = 0x00,
    ORDER_MARK              = 0x01
}EOrderFlag;

template <class Lev1State, class Lev2State, class SignalType, class Instance, class MsgType>
struct StateTransition
{
    Lev1State   lev1State;
    Lev2State   lev2State;
    SignalType	msgId;
    void (Instance::*callback)(MsgType *msg);
};

class CElevatorSrv
{
public:
    ~CElevatorSrv();

    void Init();

    static CElevatorSrv* GetInstance();

    void Run();

    void Stop();

    void AddOrderTable(STakeOrderInfo *pInfo);

    void AddArriveTable(int floor);

    /* 发送到ProcessMsg消息，供外部调用 */
    void SendCmd(SMsgPacket *pMsg);

    void SetStart(bool state) { mStart = state; }

    bool IsStart() { return mStart; }

    /* 更新电梯一级状态 */
    void UpdateLev1State(EElevatorDoorState state);

    EElevatorDoorState GetLev1State() { return mCurLev1State; }

    /* 更新电梯二级状态 */
    void UpdateLev2State(EElevatorRunState state);

    EElevatorRunState GetLev2State() { return mCurLev2State; }

    // 设置当前所处楼层
    void SetCurrentFloor(int floor) { mCurrentFloor = floor; }

    int GetCurrentFloor() { return mCurrentFloor; }

    // 清理当前楼层的向上预定
    void ClearOrderUp(int index) { mOrderUpTable[index] = ORDER_CLEAR; }

    // 清理当前楼层的向下预定
    void ClearOrderDown(int index) { mOrderDownTable[index] = ORDER_CLEAR; }

    bool IsArrivalFloor();

    void ClearArrival(int index) { mArriveTable[index] = ORDER_CLEAR; }

    // 查询当前楼层上行需求
    bool GetCurrentFloorUpRequire();

    // 查询当前楼层下行需求
    bool GetCurrentFloorDownRequire();

    // 设置当前预定上行的最大值
    void SetOrderHighestFloor(int floor) { mOrderHighestFloor = floor; }

    int GetOrderHighestFloor();

    // 更新需求楼层范围
    void UpdateRequireRange();

    // 查询是否存在需求
    bool ExistRequire();

    // 查看当前指定楼层预定
    void ShowOrderTable(int min, int max);

    // 设置当前预定下行的最大值
    void SetOrderShortestFloor(int floor) { mOrderShortestFloor = floor; }

    int GetOrderShortestFloor();

    // 停止运行
    void SetQuit(bool quit) { mQuit = quit; }

    bool IsQuit() { return mQuit; }

    void PowerOn(SMsgPacket *pMsg);

    void PowerOff(SMsgPacket *pMsg);

    void MoveUp(SMsgPacket *pMsg);

    void MoveDown(SMsgPacket *pMsg);

    void OpenDoor();

    void CloseDoor();

    void Idle(SMsgPacket *msg);

private:
    static StateTransition <EElevatorDoorState,
                            EElevatorRunState,
                            EMsgType,
                            CElevatorSrv,
                            SMsgPacket> mStateTable[];
    bool mIsFull;
    bool mQuit;                             // 退出线程控制
    bool mStart;
    int  mCurrentFloor;
    int  mOrderHighestFloor;                // 当前需求最高楼层
    int  mOrderShortestFloor;               // 当前需求最矮楼层
    std::thread mRunTid;
    EElevatorDoorState mCurLev1State;
    EElevatorRunState  mCurLev2State;
    char mArriveTable[MAX_FLOOR];           // 电梯内预定到达楼层表
    char mOrderUpTable[MAX_FLOOR];          // 所有上行预定表 0: 无预定 1: 有预定
    char mOrderDownTable[MAX_FLOOR];        // 所有下行预定表

    CElevatorSrv();

    /* 状态匹配 */
    void ProcessMsg(SMsgPacket *pMsg);

    /* 消息响应函数 */
    void MsgRespondInit(SMsgPacket *pMsg);
    void MsgRespondShutdown(SMsgPacket *pMsg);
    void MsgRespondOrderUpIdle(SMsgPacket *pMsg);
    void MsgRespondOrderUp(SMsgPacket *pMsg);
    void MsgRespondArriveFloor(SMsgPacket *pMsg);
    void MsgRespondOrderDownIdle(SMsgPacket *pMsg);
    void MsgRespondOrderDown(SMsgPacket *pMsg);
    void MsgRespondExit(SMsgPacket *pMsg);
    void MsgRespondIgnore(SMsgPacket *pMsg);
};

#endif
